﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "Event.h"
#include "IType.h"
#include "IUiView.h"
#include "IFamily.h"
#include "IInstance.h"
#include "IInstance.h"
#include "ElementId.h"
#include "ISelection.h"
#include "IModelView.h"
#include "IParameter.h"
#include "ISelection.h"
#include "IUiManager.h"   
#include "IModelView.h"
#include "IMainWindow.h"
#include "IUiDocument.h"
#include "IHighlights.h"
#include "IFamilyType.h"
#include "IApplication.h"
#include "IGenericType.h"
#include "IUiViewEvent.h"
#include "IDockManager.h"
#include "IInstanceType.h"
#include "ParameterType.h"
#include "IFamilyManager.h"
#include "IDrawingLayout.h"
#include "IGenericElement.h"
#include "IUserTransaction.h"
#include "IDrawingViewport.h"
#include "IUiDocumentEvent.h"
#include "CommandParameters.h"
#include "ILinkElementProxy.h"
#include "IGraphicsMaterial.h"
#include "IElementParameters.h"
#include "FamilyElementUtils.h"
#include "IPropertyPanelEvent.h"
#include "IParameterValidator.h"
#include "NestedInstanceUtils.h"
#include "UserTransactionUtils.h"
#include "IElementsChangeEvent.h"
#include "ILinkDocumentElement.h"
#include "IDrawingViewportType.h"
#include "IParameterDefinition.h"
#include "IParameterValueString.h"
#include "IDrawingLayoutManager.h"
#include "IParameterGroupSorter.h"
#include "ISelectionChangeEvent.h"
#include "IUiDocumentViewManager.h"
#include "IParameterGroupsFilter.h"
#include "IGraphicsNodeReference.h"
#include "IPresetParameterManager.h"
#include "IPropertyPanelEventArgs.h"
#include "IParameterValueElementId.h"
#include "IElementsChangeEventArgs.h"
#include "IElementBasicInformation.h"
#include "IElementParameterBindings.h"
#include "IFamilyGeometryConstraint.h"
#include "IPropertyPanelEventHandler.h"
#include "IEndOfTransactionProcessor.h"
#include "IParameterDefinitionLibrary.h"
#include "IParameterDefinitionLibrary.h"
#include "IElementParameterGroupOverride.h"
#include "GcmpBuiltInParameterDefinitions.h"
#include "IElementParameterGroupSorterManager.h"

#include "DocumentUtils.h"
#include <UiCommonDialog.h>
//#include "ModelViewDlg.h"
#include "ParameterUtils.h"
#include "PropertyPalette.h"
#include "FamilyTypeDialogUtils.h"
#include "PropertyInstanceWidget.h"
#include "IParameterDisplayEditbox.h"
#include "IParameterDisplayManager.h"
#include "ParameterDisplayColorList.h"
#include "IParameterDisplayCheckbox.h"
#include "ITypeGetAndSwitchBehavior.h"
#include "PropertyComponentTypeWidget.h"
#include "IParameterDisplayDropdownList.h"
#include "PropertyPaletteUiDocEventHandler.h"
#include "PropertyPaletteUiViewEventHandler.h"
#include "IParameterDisplayEditboxWithButton.h"
#include "PropertyPaletteSelectionChangeEventHandler.h"

#ifdef UiAdapter_IMPL
#include "UiAdapter.h"
#endif
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;
using namespace Sample;


class SelElementChangeObserver : public IElementsChangeEventHandler
{
public:
    SelElementChangeObserver(PropertyPalette* pPropertyPalette)
        :m_pPropertyPalette(pPropertyPalette)
    {
        DBG_WARN_UNLESS(pPropertyPalette != nullptr, L"pPropertyPalette不能为空",L"GDMP",L"2023-10-20");
    }
private:
    SelElementChangeObserver()
    {
    }
    bool IsPossibleChangePropertyPalette(const IElement * element)
    {
        if (!element)
        {
            return false;
        }
        if (const IModelView* pmodelview = quick_cast<IModelView>(element))
        {
            return false;
        }
        return true;
    }
    void On(IElementsChangeEventArgs* pArgs) override
    {
        if (!pArgs || !m_pPropertyPalette)
            return;

        if (m_pPropertyPalette->IsDockTopWidget() == false || m_pPropertyPalette->m_isNeedUpdate == true)
            return;

        const std::unordered_set<gcmp::ElementId, gcmp::ElementIdHash> & selElements = m_pPropertyPalette->GetSourceElementsFast().empty()
            ? m_pPropertyPalette->GetSelectedElementsFast() : m_pPropertyPalette->GetSourceElementsFast();
        if (selElements.empty())
            return;

        const std::vector<const IElement*> &elements = pArgs->GetElements();
        FOR_EACH(element, elements)
        {
            if (!IsPossibleChangePropertyPalette(element))
            {
                continue;
            }

            ElementId id = element->GetBasicInformation()->GetElementId();
            if (selElements.find(id) != selElements.end())
            {
                m_pPropertyPalette->m_isNeedUpdate = true;
                break;
            }
        }
    }

private:
    PropertyPalette* m_pPropertyPalette;
};

// 文档事务提交监听，用于触发更新属性表时机
class EndOfTransactionProcessorPropertyPalette : public gcmp::IEndOfTransactionProcessor
{
public:
    EndOfTransactionProcessorPropertyPalette(PropertyPalette* pPropertyPalette)
        :m_pPropertyPalette(pPropertyPalette), m_id(IEndOfTransactionProcessor::GenerateId())
    {
        DBG_WARN_UNLESS(pPropertyPalette != nullptr, L"pPropertyPalette不能为空",L"GDMP",L"2023-10-20");
    }
public:
    virtual void Process(IDocument* pDoc) override
    {
        if (m_pPropertyPalette->m_isNeedUpdate //事务提交且属性表需要更新，则立即更新
            && !m_pPropertyPalette->m_bTransactionIsCommitting // 防止属性面板正在刷新的时候刷新函数重入
            )
        {
            m_pPropertyPalette->Refresh(false);
        }
    }

    virtual Int64 GetId() const override { return m_id; }

private:
    Int64 m_id;
    PropertyPalette* m_pPropertyPalette;
};

//////////////////////////////////////////////////////////////////////////
// 属性表修改事件
namespace Sample
{
    class PropertyPanelEventArgs : public IPropertyPanelEventArgs
    {
    public:
        PropertyPanelEventArgs(const std::wstring& type, const std::wstring& newValue)
            : m_pEvent(nullptr)
            , m_type(type)
            , m_uniqueID(L"")
            , m_newValue(newValue)
        {
        }

        virtual const IEvent* GetEvent() const override
        {
            return m_pEvent;
        }
        virtual const std::wstring& GetType() const override
        {
            return m_type;
        }
        virtual const std::wstring& GetNewValue() const override
        {
            return m_newValue;
        }

        /// \brief 得到Property属性项Id(修改属性项时有效)
        virtual void SetPropertyItemUniqueId(const std::wstring &uniqueID) override
        {
            m_uniqueID = uniqueID;
        }

        /// \brief 设置Property属性项Id(修改属性项时有效)
        virtual std::wstring GetPropertyItemUniqueId() const
        {
            return m_uniqueID;
        }

        void SetEvent(const IEvent* pEvent)
        {
            m_pEvent = pEvent;
        }
    private:
        const IEvent *                     m_pEvent;
        std::wstring                       m_type;
        std::wstring                       m_newValue;
        std::wstring                       m_uniqueID; //Item uId
    };

    class PropertyPanelEvent : public gcmp::Event<IPropertyWidget, IPropertyPanelEvent, IPropertyPanelEventHandler, PropertyPanelEventArgs>
    {
    public:
        PropertyPanelEvent(const std::wstring& name, IPropertyWidget* pSender)
            : gcmp::Event<IPropertyWidget, IPropertyPanelEvent, IPropertyPanelEventHandler, PropertyPanelEventArgs>(name, pSender)
        {
        }
    };
}

//////////////////////////////////////////////////////////////////////////
static bool IsCurModelViewShow(const std::vector<ElementId>& selElements)
{
    if (selElements.size() != 1)
        return false;

    IUiView* pUIView = IUiDocumentViewManager::Get()->GetCurrentUiView();
    if (pUIView == nullptr)
        return false;

    IModelView* pModelView = pUIView->GetModelView();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView != nullptr, L"pModelView不能为空",L"GDMP",L"2023-10-20");

    bool isCurView = pModelView->GetBasicInformation()->GetElementId() == selElements[0];
    return isCurView;
}
static void GetCommonParameters(IDocument* pDoc, const IElement* pEle,
    const std::vector<ElementId>& selElements,
    /*[out]*/std::vector<OwnerPtr<IParameter>>& params,
    /*[out]*/std::vector<bool>& paramMultiVals)
{
    //如果选择集中有多个构件，只有当选择集中的构件都是ILinkElementProxy或都不是ILinkElementProxy才显示参数
    if ((int)selElements.size() > 1)
    {
        const ILinkElementProxy* pProxy = quick_cast<ILinkElementProxy>(pEle);
        if (pProxy)
        {
            for (int i = 1; i < (int)selElements.size(); ++i)
            {
                const IElement* pSelEle = pDoc->GetElement(selElements[i]);
                const ILinkElementProxy* pLinkElementProxy = quick_cast<ILinkElementProxy>(pSelEle);
                if (pLinkElementProxy == nullptr)
                    return;
            }
        }
        else
        {
            for (int i = 1; i < (int)selElements.size(); ++i)
            {
                const IElement* pSelEle = pDoc->GetElement(selElements[i]);
                const ILinkElementProxy* pLinkElementProxy = quick_cast<ILinkElementProxy>(pSelEle);
                if (pLinkElementProxy)
                    return;
            }
        }
    }

    //先根据参数类型找到公共参数
    std::vector<int> paramDefs;
    std::vector<const IElement*> otherSelEles;
    const IElementParameters* pElementParameters = pEle->GetElementParameters();
    if (pElementParameters)
        pElementParameters->ReportParameterDefinitions(&paramDefs);

    // 参数去重
    {
        std::vector<int> paramDefsNoDup;
        FOR_EACH(tmpParamId, paramDefs)
        {
            if (std::find(paramDefsNoDup.begin(), paramDefsNoDup.end(), tmpParamId) == paramDefsNoDup.end())
                paramDefsNoDup.push_back(tmpParamId);
        }

        paramDefs.swap(paramDefsNoDup);
    }

    for (int i = 1; i < (int)selElements.size(); ++i)
    {
        const IElement* pSelEle = pDoc->GetElement(selElements[i]);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pSelEle != nullptr, L"pSelEle为空",L"GDMP",L"2023-10-20");
        otherSelEles.push_back(pSelEle);

        std::vector<int> otherSelParams;
        const IElementParameters* pElementParameters1 = pSelEle->GetElementParameters();
        if (pElementParameters1)
            pElementParameters1->ReportParameterDefinitions(&otherSelParams);
        for (auto itr = paramDefs.begin(); itr != paramDefs.end(); )
        {
            if (std::find(otherSelParams.begin(), otherSelParams.end(), *itr) == otherSelParams.end())
            {
                itr = paramDefs.erase(itr);
            }
            else
            {
                ++itr;
            }
        }
    }

    bool isCurViewShow = IsCurModelViewShow(selElements);
    //根据值是否相同判断是否多值,有对象不显示该参数，公共也不显示。
    FOR_EACH(paramDefItem, paramDefs)
    {
        OwnerPtr<IParameter> opCurParam;
        if (pEle->GetElementParameters())
            opCurParam = pEle->GetElementParameters()->GetParameterById(paramDefItem);
        if (!IParameter::IsValidParameter(opCurParam))
            continue;

        if (opCurParam->GetParameterDefinition()->GetParameterTypeId() == PARAMETER_TYPE(None)) //当前参数不显示
        {
            if (isCurViewShow)
            {
                if (opCurParam->GetParameterDefinitionUid() != PARAMETER_UID(ElementNameBuiltInParameter))
                    continue;
            }
            else
            {
                continue;
            }
        }

        bool isDisplay = true;
        bool isMultiValue = false;
        for (auto itr = otherSelEles.begin(); itr != otherSelEles.end(); ++itr)
        {
            OwnerPtr<IParameter> otherParam;
            if ((*itr)->GetElementParameters())
                otherParam = (*itr)->GetElementParameters()->GetParameterById(paramDefItem);
            if (IParameter::IsValidParameter(otherParam) == false ||
                otherParam->GetParameterDefinition()->GetParameterTypeId() == PARAMETER_TYPE(None))//当前参数不显示
            {
                isDisplay = false;
                break;
            }

            if (isMultiValue == false &&
                opCurParam->GetParameterValueStorage()->HasSameValue(otherParam->GetParameterValueStorage()) == false)
            {
                isMultiValue = true;
            }
        }

        if (isDisplay == false)//当前参数不显示
            continue;

        params.push_back(TransferOwnership(opCurParam));
        paramMultiVals.push_back(isMultiValue);
    }
}

PropertyPalette::PropertyPalette()
    : Sample::CPropertyWidget(nullptr)
    , m_isTopVisible(false)
    , m_isNeedUpdate(false)
    , m_endOfTransactionProcessorId(-1)
    , m_upUserTransaction(nullptr)
    , m_elementChangeObserver(nullptr)
    , m_uiDocumentEventHandler(NEW_AS_OWNER_PTR(PropertyPaletteUiDocEventHandler))
    , m_uiViewEventHandler(NEW_AS_OWNER_PTR(PropertyPaletteUiViewEventHandler))
    , m_selectionChangeEventHandler(NEW_AS_OWNER_PTR(PropertyPaletteSelectionChangeEventHandler))
    , m_defaultElementId(ElementId::InvalidID)
    , m_curUiDocId(-1)
    , m_bTransactionIsCommitting(false)
    , m_canPropertyTableBeUpdated(true)
{
    setObjectName(QStringLiteral("PropertyPalette"));
    m_elementChangeObserver = NEW_AS_OWNER_PTR(SelElementChangeObserver, this);
    /*/
    // 这里将来扩展材质相关的内容
    PropertyPaletteEventHandler::GetInstance();
    */

    // 初始化事件处理
    ISelection::Get()->GetSelectionChangeEvent()->Add(m_selectionChangeEventHandler.get());
    IUiDocumentViewManager::Get()->GetUiDocumentEvent()->Add(m_uiDocumentEventHandler.get());
    IUiDocumentViewManager::Get()->GetUiViewEvent()->Add(m_uiViewEventHandler.get());

    setApplyButtonText(QString::fromStdWString(GBMP_TR(L"应用")));

    connect(this, SIGNAL(sigPropertyBindButtonClicked(int)), this, SLOT(OnPropertyBindButtonClicked(int)), Qt::UniqueConnection);
    connect(this, SIGNAL(sigPropertyEditButtonClicked(int)), this, SLOT(onPropertyEditButtonClicked(int)), Qt::UniqueConnection);
    connect(this, SIGNAL(DropDownListIndexChange(int, int)), this, SLOT(OnDropDownListIndexChange(int, int)), Qt::UniqueConnection);
    m_inputEvent = NEW_AS_OWNER_PTR(PropertyPanelEvent, L"PropertyPanelEvent", this);

    setMinimumWidth(230);
}

PropertyPalette::~PropertyPalette()
{
}

QSize PropertyPalette::sizeHint() const
{
    return QSize(230, 900);
}

void PropertyPalette::RefreshAll()
{
    QWidget *parent = dynamic_cast<QWidget*>(this->parent());
    bool IsDockTopWidget = isVisible() && parent != nullptr && parent->isVisible();

    //如窗口隐藏，没必要继续刷新
    if (!IsDockTopWidget)
    {
        return;
    }

    UpdateComponentType();// 更新类型列表
    UpdatePropertyTable(true);// 刷新属性表
}

void PropertyPalette::AttachElementChangeObserver(gcmp::IUiView* pUIView)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIView != nullptr, L"pUIView不能为空",L"GDMP",L"2023-10-20");
    IUiDocument* pUIDoc = pUIView->GetUiDocument();
    if (pUIDoc)
    {
        gcmp::IDocument* pDoc = pUIDoc->GetDbDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"doc不能为空",L"GDMP",L"2023-10-20");

        pDoc->AddElementsChangeEventHandler(ElementsChangeEventType::ElementsPreUpdationEvent, m_elementChangeObserver.get());

        gcmp::OwnerPtr<gcmp::IEndOfTransactionProcessor> opEndOfTransactionProcessor = NEW_AS_OWNER_PTR(EndOfTransactionProcessorPropertyPalette, this);
        m_endOfTransactionProcessorId = opEndOfTransactionProcessor->GetId();
        UserTransactionUtils::AddEndOfProcessorAfterRegenerateAll(pDoc, TransferOwnership(opEndOfTransactionProcessor));
    }
}

void PropertyPalette::DetachElementChangeObserver(gcmp::IUiView* pUIView)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIView != nullptr, L"pUIView不能为空",L"GDMP",L"2023-10-20");
    IUiDocument* pUIDoc = pUIView->GetUiDocument();
    if (pUIDoc)
    {
        gcmp::IDocument* pDoc = pUIDoc->GetDbDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc不能为空",L"GDMP",L"2023-10-20");

        pDoc->DeleteElementsChangeEventHandler(ElementsChangeEventType::ElementsPreUpdationEvent, m_elementChangeObserver.get());

        UserTransactionUtils::DeleteEndOfProcessor(pDoc, m_endOfTransactionProcessorId);
    }
}

void PropertyPalette::CheckDocSwitched()
{
    gcmp::IDocument* pDoc = GetDocument();
    if (pDoc)
    {
        gcmp::RuntimeId uiDocId = pDoc->GetRuntimeId();
        if (m_defaultElementId.IsValid() && m_curUiDocId != uiDocId)
        {
            m_defaultElementId = ElementId::InvalidID;
        }
        m_curUiDocId = uiDocId;
    }
}

void PropertyPalette::showEvent(QShowEvent *event)
{
    if (IsDockTopWidget())
    {
        Refresh(false);
    }
}

bool PropertyPalette::SelectedElementsAreSameCategory(std::vector<gcmp::ElementId>& selElements)
{
    if (selElements.size() > 1)
    {
        IDocument * pDoc = GetDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"文档指针为空，不合法",L"GDMP",L"2023-10-20");

        //如果选择集中多于1个，需要判断是否为同一类构件
        IElement* firstElement = pDoc->GetElement(selElements.at(0));
        gcmp::UniIdentity firstUid = firstElement->GetBasicInformation()->GetCategoryUid();
        gcmp::IType* firstType = firstElement->GetBasicInformation()->GetType();
        FOR_EACH(eleId, selElements)
        {
            IElement* curElement = pDoc->GetElement(eleId);
            gcmp::IType* type = curElement->GetBasicInformation()->GetType();

            if (firstUid != curElement->GetBasicInformation()->GetCategoryUid())//类别不一样
            {
                return false;
            }
            else if (firstType != curElement->GetBasicInformation()->GetType())//同类别，但是类型不一样
            {
                return false;
            }
        }
    }
    return true;
}

void PropertyPalette::SetStatusOfComponentTypeComboBox()
{
    //设置类型type下拉框是否可用，默认有效
    //只对实体构件才可用
    std::vector<ElementId> selElements = GetSelectedElements();
    if (selElements.empty())
    {
        GetShowElements(selElements);
    }
    if (selElements.empty())
    {
        return;
    }
    IDocument * pDoc = GetDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"文档指针为空，不合法",L"GDMP",L"2023-10-20");

    IElement* firstElement = pDoc->GetElement(selElements[0]);
    DBG_WARN_AND_RETURN_VOID_UNLESS(firstElement != nullptr, L"Element无效",L"GDMP",L"2023-10-20");
    const ILinkElementProxy * pLinkElementProxy = quick_cast<ILinkElementProxy>(firstElement);
    if (pLinkElementProxy)
    {
        CComponentTypeWidget *pComponentTypeWidget = GetComponentTypeWidget();
        pComponentTypeWidget->setEnableComponentTypeChangeComboxGroup(false);
    }
}

void PropertyPalette::SetStatusOfAddAndModifyButton()
{
    // 设置添加、编辑构件类型的两个按钮是否可用
    // 只有对实体构件才可用
    std::vector<ElementId> selElements = GetSelectedElements();
    if (selElements.empty())
    {
        GetShowElements(selElements);
    }
    if (selElements.empty())
    {
        return;
    }
    IDocument * pDoc = GetDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"文档指针为空，不合法",L"GDMP",L"2023-10-20");

    IElement* firstElement = pDoc->GetElement(selElements[0]);
    DBG_WARN_AND_RETURN_VOID_UNLESS(firstElement != nullptr, L"Element无效",L"GDMP",L"2023-10-20");
    IElementBasicInformation* pBasicInformation = firstElement->GetBasicInformation();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pBasicInformation, L"pBasicInformation为空",L"GDMP",L"2023-10-20");
    if (IType* firstType = pBasicInformation->GetType())
    {
        CComponentTypeWidget *pComponentTypeWidget = GetComponentTypeWidget();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pComponentTypeWidget != nullptr, L"CComponentTypeWidget为空",L"GDMP",L"2023-10-20");
        pComponentTypeWidget->setEnableComponentTypeAddButton(false);
        pComponentTypeWidget->setEnableComponentTypeModifyButton(false);

        if ((IsA<IInstanceType>(firstType) || IsA<IGenericType>(firstType) || IsA<IDrawingViewportType>(firstType)) && SelectedElementsAreSameCategory(selElements))
        {
            if (IsA<IInstanceType>(firstType))
            {
                pComponentTypeWidget->setEnableComponentTypeAddButton(true);
            }
            pComponentTypeWidget->setEnableComponentTypeModifyButton(true);
        }
    }
}

gcmp::IDocument*  PropertyPalette::GetDocument()
{
    IUiDocument* pUIDoc = IUiDocumentViewManager::Get()->GetCurrentUiDocument();
    if (pUIDoc)
    {
        return pUIDoc->GetDbDocument();
    }

    return nullptr;
}

bool PropertyPalette::IsDockTopWidget()
{
    QWidget *parent = dynamic_cast<QWidget*>(this->parent());
    return isVisible() && parent != nullptr && parent->isVisible();
}

void PropertyPalette::GetShowElements(std::vector<ElementId>& selElements)
{
    gcmp::IDocument* pDocument = GetDocument();
    if (!pDocument)
    {
        return;
    }

    selElements = GetSourceElements().empty() ? GetSelectedElements() : GetSourceElements();
    if (selElements.empty())
    {
        if (m_defaultElementId.IsValid())
        {
            selElements.push_back(m_defaultElementId);
        }
        else
        {
            ElementId elementId;
            /*/ TODO 需要之后添加的
            ///////////////判断是否是通过视口创建的
            ModelViewDlg* pModelViewDlg = dynamic_cast<ModelViewDlg*>(IModelViewDlg::Get(GBMP_MODELVIEW_DLG_NAME));
            QTreeWidgetItem* pSelectedPaperItem = pModelViewDlg->GetSelectedViewPort();
            if (pSelectedPaperItem)
            {
                std::wstring errorMessage = L"";
                const IDrawingLayoutManager* pLayoutsManager = IDrawingLayoutManager::Get(pDocument, &errorMessage);
                DBG_WARN_AND_RETURN_VOID_UNLESS(pLayoutsManager, L"pLayoutsManager为空",L"GDMP",L"2023-10-20");
                IDrawingViewport* pViewPort = pLayoutsManager->GetLayout(pSelectedPaperItem->parent()->text(0).toStdWString())->GetViewport(pSelectedPaperItem->text(0).toStdWString());
                IElement* pElement = pViewPort->GetOwnerElement();
                elementId = pElement->GetBasicInformation()->GetElementId();
            }
            else
            {
            */
            IUiView* pUIView = IUiDocumentViewManager::Get()->GetCurrentUiView();
            //DBG_WARN_AND_RETURN_VOID_UNLESS(pUIView != nullptr, L"GetCurrentUiView()为空", L"GDMP",L"2023-10-20");
            if (pUIView == nullptr)
                return;

            IModelView* pModelView = pUIView->GetModelView();
            //DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView != nullptr, L"pModelView不能为空", L"GDMP",L"2023-10-20");
            if (pModelView == nullptr)
                return;

            if (pModelView->GetViewType() == BuiltInViewType::Drawing && !pDocument->IsFamilyDocument())
            {
                std::wstring name = pModelView->GetName();
                std::wstring errorMessage = L"";
                const IDrawingLayoutManager* pLayoutsManager = IDrawingLayoutManager::Get(pDocument, &errorMessage);
                DBG_WARN_AND_RETURN_VOID_UNLESS(pLayoutsManager, L"layoutManager为空",L"GDMP",L"2023-10-20");
                IDrawingLayout* pLayout = pLayoutsManager->GetLayout(name);
                DBG_WARN_AND_RETURN_VOID_UNLESS(pLayout, L"layout为空",L"GDMP",L"2023-10-20");
                IGenericElement* pGenericElement = quick_cast<IGenericElement>(pLayout->GetOwnerElement());
                DBG_WARN_AND_RETURN_VOID_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMP",L"2023-10-20");
                elementId = pGenericElement->GetBasicInformation()->GetElementId();
            }
            else
            {
                elementId = pModelView->GetBasicInformation()->GetElementId();
            }
            ///////////////判断是否是通过视口创建的

            //selElements.push_back(pModelView->GetBasicInformation()->GetElementId());
            selElements.push_back(elementId);
        }
    }
}

const std::unordered_set<gcmp::ElementId, gcmp::ElementIdHash> & PropertyPalette::GetSourceElementsFast()
{
    static std::unordered_set<gcmp::ElementId, gcmp::ElementIdHash> sourceElements;
    sourceElements.clear();
    //预设参数Element
    if (GetPreSetElementId().IsValid())
    {
        sourceElements.emplace(GetPreSetElementId());
    }
    return sourceElements;
}

std::vector<gcmp::ElementId> PropertyPalette::GetSourceElements()
{
    std::vector<ElementId> sourceElements;
    //预设参数Element
    if (GetPreSetElementId().IsValid())
    {
        sourceElements.emplace_back(GetPreSetElementId());
    }
    return sourceElements;
}

std::vector<gcmp::ElementId> PropertyPalette::GetSelectedElements()
{
    std::vector<ElementId> resultElements;
    if (!GetDocument())
        return resultElements;

    DBG_WARN_AND_RETURN_UNLESS(ISelection::Get(), resultElements, L"ISelection::Get() is nullptr!",L"GDMP",L"2023-10-20");
    const GraphicsNodeReferenceOwnerPtrSet& nodeRefs = ISelection::Get()->GetGraphicsNodeReferences();
    resultElements.reserve(nodeRefs.size());
    std::set<ElementId> nestedInstanceIds;
    FOR_EACH(selItem, nodeRefs)
    {
        DBG_WARN_AND_CONTINUE_UNLESS(selItem, L"selItem is nullptr!",L"GDMP",L"2023-10-20");
        ElementId selectedId = selItem->GetElementId();

        IInstance * pInstance = DocumentUtils::GetElement<IInstance>(GetDocument(), selectedId);
        if (!pInstance)
        {
            resultElements.emplace_back(selectedId);
            continue;
        }

        // 嵌套族构件相关
        if (ElementId::InvalidID != pInstance->GetSuperInstanceId() || !pInstance->GetSubInstanceIds().empty())
        {
            nestedInstanceIds.insert(selectedId);
            continue;
        }

        resultElements.emplace_back(selectedId);
    }

    for (auto& id : nestedInstanceIds)
    {
        IInstance * pInstance = DocumentUtils::GetElement<IInstance>(GetDocument(), id);
        DBG_WARN_AND_CONTINUE_UNLESS(pInstance, L"pInstance is nullptr!",L"GDMP",L"2023-10-20");

        if (pInstance->GetSuperInstanceId() != ElementId::InvalidID)
        {
            if (nestedInstanceIds.find(pInstance->GetSuperInstanceId()) == nestedInstanceIds.end())
                resultElements.emplace_back(id);
        }
        else
            resultElements.emplace_back(id);
    }

    return resultElements;
}

const std::unordered_set<gcmp::ElementId, gcmp::ElementIdHash> & PropertyPalette::GetSelectedElementsFast()
{
    static std::unordered_set<gcmp::ElementId, gcmp::ElementIdHash> selElements;
    if (GetDocument())
    {
        ISelection* pSelection = ISelection::Get();
        if (pSelection)
        {
            //多选Element   
            return pSelection->GetSelectedElements();
        }
    }
    return selElements;
}

void PropertyPalette::OnAddComponentTypeBottonClick()
{
    //点击添加构件类型时发出信号
    IUiDocument* pCurDoc = IUiDocumentViewManager::Get()->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurDoc != nullptr, L"没有当前的UIDoc",L"GDMP",L"2023-10-20");
    FamilyTypeDialogUtils::CmdNewFamilyTypeDialog(pCurDoc);

    //更新属性表类型框
    UpdateComponentType();
}

void PropertyPalette::OnModifyComponentBottonClick()
{
    //点击修改构件类型按钮时发出信号
    IUiDocument* pCurDoc = IUiDocumentViewManager::Get()->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurDoc != nullptr, L"没有当前的UIDoc",L"GDMP",L"2023-10-20");
    if (!FamilyTypeDialogUtils::CmdShowTypePropertyDialog(pCurDoc))
    {
        return;
    }

    //更新属性表类型框
    UpdateComponentType();

    // 通知Action类型更新
    {
        std::vector<ElementId> selectedEles = GetSourceElements().empty() ? GetSelectedElements() : GetSourceElements();
        if (!selectedEles.empty())
        {
            gcmp::IDocument* pDocument = GetDocument();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pDocument, L"文档指针为空，不合法！",L"GDMP",L"2023-10-20");
            IElement* pElement = pDocument->GetElement(selectedEles[0]);
            if (pElement)
            {
                const IType* pType = pElement->GetBasicInformation()->GetType(); // 簇类型
                DBG_WARN_AND_RETURN_VOID_UNLESS(pType != nullptr,L"没有Type的Element的代码处理不应该允许到这里，CmdShowTypePropertyDialog()应该返回false并return",L"GDMP",L"2023-10-20");
                const std::wstring typeName = pType->GetBasicInformation()->GetName();

                PropertyPanelEventArgs inputArgs(L"ComponentTypeModified", typeName);
                inputArgs.SetPropertyItemUniqueId(this->GetComponentTypeModifiedPropertyEventId());
                m_inputEvent->Emit(&inputArgs);
            }
        }
    }
}

namespace
{
    bool SwitchTypeOfElement(IType* pNewType, IElement* pElement)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pNewType && pElement, L"invalid input arguments.",L"GDMP",L"2023-10-20");

        IGenericType* pGenericType = quick_cast<IGenericType>(pNewType);
        IInstanceType* pInstanceType = quick_cast<IInstanceType>(pNewType);
        if (pGenericType)
        {
            if (pNewType->GetElementId() == pElement->GetBasicInformation()->GetTypeId())
                return true;

            bool changedSuccess = pElement->GetBasicInformation()->SetTypeId(pNewType->GetElementId());
            if (changedSuccess)
            {
                pElement->FinishEditing();
            }

            return changedSuccess;
        }
        else if (pInstanceType)
        {
            if (pNewType->GetElementId() == pElement->GetBasicInformation()->GetTypeId())
                return true;

            bool changedSuccess = false;
            IInstance* pInstance = quick_cast<IInstance>(pElement);
            if (pInstance && pInstance->ChangeTypeTo(pNewType->GetElementId()))
            {
                changedSuccess = true;
            }
            else if (pElement->GetBasicInformation()->SetTypeId(pNewType->GetElementId()))
            {
                changedSuccess = true;
            }

            if (changedSuccess)
            {
                pElement->FinishEditing();
            }

            return changedSuccess;
        }
        else
        {
            DBG_WARN_AND_RETURN_FALSE_UNLESS(false, L"invalid type.",L"GDMP",L"2023-10-20");
        }
    }
}

// 点击不同的构件类型触发的事件
void PropertyPalette::OnSelectComponentType(const CComponentTypeItem *pComponentTypeItem)
{
    gcmp::IDocument* pDocument = GetDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDocument, L"pDocument为空",L"GDMP",L"2023-10-20");
    if (!pDocument || !pComponentTypeItem)
    {
        return;
    }

    std::vector<ElementId> selElements = GetSourceElements().empty() ? GetSelectedElements() : GetSourceElements();
    DBG_WARN_AND_RETURN_VOID_UNLESS(selElements.empty() == false, L"SelectedElements为空",L"GDMP",L"2023-10-20");
    IElement* pElement = pDocument->GetElement(selElements[0]);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"pElement不能为空",L"GDMP",L"2023-10-20");
    IType* pOldType = pElement->GetBasicInformation()->GetType();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pOldType, L"无法获取到有效的ElementType",L"GDMP",L"2023-10-20");

    if (m_upUserTransaction == nullptr)
    {
        m_upUserTransaction = IUserTransaction::Create(pDocument, GBMP_TR(L"修改构件属性"), true);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_upUserTransaction, L"m_upUserTransaction为空",L"GDMP",L"2023-10-20");
    }
    if (m_upUserTransaction->IsStarted() == false)
    {
        m_upUserTransaction->Start();
    }

    bool isChangedType = false;

    IInstanceType* pInstanceType = quick_cast<IInstanceType>(pOldType);
    if (pInstanceType && pInstanceType->IsSub())
    {
        const std::vector<Int64>& pSubFamilyIdPath = pInstanceType->GetSubFamilyIdPath();
        FOR_EACH(selEle, selElements)
        {
            IInstance* pSubInstance = quick_cast<IInstance>(pDocument->GetElement(selEle));
            DBG_WARN_AND_CONTINUE_UNLESS(pSubInstance && pSubInstance->GetSuperInstanceId().IsValid(), L"pSubInstance不能为空",L"GDMP",L"2023-10-20");

            //PS: 这里还是以单个element传到behavior去进行实际切换， 
            //    是因为预设参数的相关逻辑不好处理，待属性面板重构后， 
            //    决定是否将选择集整体传入SwitchTypeOfElement接口。 -- zhangl-al
            //isChangedType = pTypeBehavior->SwitchTypeOfElement(pElement);
            isChangedType = NestedInstanceUtils::SwitchSubInstanceToType(pSubInstance, pSubFamilyIdPath, pComponentTypeItem->Name().toStdWString());

            if (GetPreSetElementId().IsValid())
            {
                IPresetParameterManager* pPreSetMgr = IPresetParameterManager::Get(pDocument);
                DBG_WARN_AND_RETURN_VOID_UNLESS(pPreSetMgr, L"pPreSetMgr为空",L"GDMP",L"2023-10-20");

                Int32 categorySecondkey = pPreSetMgr->GetPresetValuesGroupId(pSubInstance);

                if (pPreSetMgr->SetPresetType(pSubInstance->GetBasicInformation()->GetCategoryUid(), categorySecondkey, pSubInstance->GetBasicInformation()->GetTypeId()))
                    isChangedType = true;
            }
        }
    }
    else
    {
        //获取要切换的目标类型
        IType* pNewType = nullptr;
        std::vector<IType*>  allElement = Sample::DocumentUtils::GetTypiesByCategory(pDocument, pOldType->GetBasicInformation()->GetCategoryUid());
        FOR_EACH(itemEle, allElement)
        {
            if (itemEle->GetElementId().AsInt64() == pComponentTypeItem->UniqueID())
            {
                pNewType = itemEle;
                break;
            }
        }

        DBG_WARN_AND_RETURN_VOID_UNLESS(pNewType, L"无法在同一个Category下找到目标类型",L"GDMP",L"2023-10-20");

        FOR_EACH(selEle, selElements)
        {
            IElement * pElement = pDocument->GetElement(selEle);
            DBG_WARN_AND_CONTINUE_UNLESS(pElement, L"pElement不能为空",L"GDMP",L"2023-10-20");

            //PS: 这里还是以单个element传到behavior去进行实际切换， 
            //    是因为预设参数的相关逻辑不好处理，待属性面板重构后， 
            //    决定是否将选择集整体传入SwitchTypeOfElement接口。
            //isChangedType = pTypeBehavior->SwitchTypeOfElement(pElement);
            isChangedType = SwitchTypeOfElement(pNewType, pElement);

            if (GetPreSetElementId().IsValid())
            {
                IPresetParameterManager* pPreSetMgr = IPresetParameterManager::Get(pDocument);
                DBG_WARN_AND_RETURN_VOID_UNLESS(pPreSetMgr, L"pPreSetMgr为空",L"GDMP",L"2023-10-20");

                Int32 categorySecondkey = pPreSetMgr->GetPresetValuesGroupId(pElement);

                if (pPreSetMgr->SetPresetType(pElement->GetBasicInformation()->GetCategoryUid(), categorySecondkey, pElement->GetBasicInformation()->GetTypeId()))
                    isChangedType = true;
            }
        }
    }

    //标记不需要更新整个属性表，避免提交事务导致更新
    m_isNeedUpdate = false;
    if (isChangedType)
    {
        m_bTransactionIsCommitting = true;
        m_upUserTransaction->Commit();
        m_bTransactionIsCommitting = false;
    }
    else
        m_upUserTransaction->Rollback();

    //更新属性表
    UpdatePropertyTable();

    //更新可视化
    UpdateViewVisual();

    if (isChangedType)
    {
        PropertyPanelEventArgs inputArgs(L"ComponentTypeSelectChanged", StringUtil::ToWString(pComponentTypeItem->UniqueID()));
        inputArgs.SetPropertyItemUniqueId(this->GetComponentTypeChangedEventId());
        m_inputEvent->Emit(&inputArgs);
    }
}

std::wstring PropertyPalette::GetComponentTypeChangedEventId() const
{
    return L"PropertyPaletteComponentTypeChangedEvent";
}
std::wstring PropertyPalette::GetComponentTypeModifiedPropertyEventId() const
{
    return L"PropertyPaletteComponentTypeModifiedPropertyEvent";
}

PropertyPalette* PropertyPalette::GetPropertyPalette()
{
    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiManager, L"pUiManager为空",L"GDMP",L"2023-10-20");
    IDockManager* pDockManager = pUiManager->GetDockManager();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDockManager, L"pDockManager为空",L"GDMP",L"2023-10-20");
    IDock* pDock = pDockManager->GetDock(GetTypeName());
    if (!pDock)
        return nullptr;
    PropertyPalette* pPropPalette = dynamic_cast<PropertyPalette*>(pDock->GetWidget());
    return pPropPalette;
}

void PropertyPalette::DisplayPanel()
{
    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiManager, L"pUiManager为空",L"GDMP",L"2023-10-20");
    IDockManager* pDockManager = pUiManager->GetDockManager();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDockManager, L"pDockManager为空",L"GDMP",L"2023-10-20");

    IDock* pDock = pDockManager->GetDock(IPropertyWidget::GetTypeName());
    bool isNotCreate = false;
    if (!pDock)
    {
        OwnerPtr<IDock> opDock = pDockManager->CreateDock(IPropertyWidget::GetTypeName(), L"属性面板");
        OwnerPtr<IPropertyWidget> opPropertyWidget = NEW_AS_OWNER_PTR(PropertyPalette);
        opDock->SetWidget(TransferOwnership(opPropertyWidget));
        pDockManager->AddDock(TransferOwnership(opDock), DockArea::Left, DockOrientation::Vertical);
        pDock = pDockManager->GetDock(IPropertyWidget::GetTypeName());
        isNotCreate = true;
    }
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDock, L"pDock为空",L"GDMP",L"2023-10-20");
    if (!isNotCreate)
    {
        pDock->Show();
        pDock->Raise();
    }

    IPropertyWidget* pPropPalette = dynamic_cast<IPropertyWidget*>(pDock->GetWidget());
    pPropPalette->Refresh(false);
}

void PropertyPalette::OnApply()
{
    if (IsPropertyValueChanged() == false)
    {
        if (!m_bTransactionIsCommitting && m_upUserTransaction != nullptr && m_upUserTransaction->IsStarted())
        {
            m_upUserTransaction->Rollback();
        }
        return;
    }

    // 基类"应用"事件处理
    CPropertyWidget::OnApply();
    UpdatePropertyTableToElement();
}

void PropertyPalette::OnPropertyValueChanged(int groupIndex, int propertyIndex)
{
    // 基类修改属性项事件处理
    if (UpdatePropertyItemToElement(groupIndex, propertyIndex))
    {
        CPropertyWidget::OnPropertyValueChanged(groupIndex, propertyIndex);
    }
    else
    {
        Refresh(true);
    }
}

void PropertyPalette::OnDropDownListIndexChange(int groupIndex, int propertyIndex)
{
    CInstancePropertyWidget* pIPW = GetComponentInstancePropertyWidget();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pIPW != nullptr, L"pIPW为空",L"GDMP",L"2023-10-20");
    CPropertyItem* pItem = pIPW->GetPropertyByIndex(groupIndex, propertyIndex);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pItem != nullptr, L"pItem不能为空",L"GDMP",L"2023-10-20");

    PropertyPanelEventArgs args(L"PropertyItemButtonClicked", pItem->GetValue().toString().toStdWString());
    args.SetPropertyItemUniqueId(StringUtil::ToWString(pItem->UniqueID()));
    m_inputEvent->Emit(&args);
}

bool PropertyPalette::CheckParameterValid(Sample::CPropertyItem* pItem, const gcmp::IParameter* param,
    const std::vector<gcmp::ElementId>& selElements)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMP",L"2023-10-20");

    if (!pItem)
        return true;

    if (!pItem->IsEnable() || pItem->IsMultiValue())
        return false;

    GEditStyle eEditStyle = pItem->GetEditStyle();
    if ((eEditStyle != esLineEdit)
        && (eEditStyle != esPlainEdit)
        && (eEditStyle != esLineEllipsis))
        return true;

    QVariant strParamValue = pItem->GetValue();
    GEditStyle style = pItem->GetEditStyle();
    gcmp::ParameterStorageType storageTypes = param->GetParameterDefinition()->GetStorageType();
    gcmp::UniIdentity ptId = param->GetParameterDefinition()->GetParameterTypeId();

    bool isCheck = true;
    QString strValue = strParamValue.toString().trimmed();
    if (ptId == PARAMETER_TYPE(Angle) || ptId == PARAMETER_TYPE(Slope) || 
        ptId == PARAMETER_TYPE(Volume) || ptId == PARAMETER_TYPE(Area))
    {
        if (strValue.isEmpty())
        {
            return false;
        }
        else
        {
            int index = strValue.indexOf(QString::fromStdWString(GBMP_TR(L"°")));
            strValue = strValue.left(index);
            strValue.toDouble(&isCheck);
            if (!isCheck)
            {
                UiCommonDialog::ShowMessageBox(GBMP_TR(L"警告"), GBMP_TR(L"请输入数值"), (int)UiCommonDialog::ButtonType::OK);
                return false;
            }
        }
    }
    else if (!pItem->IsMultiValue())
    {
        if (storageTypes == ParameterStorageType::Bool)
        {
            isCheck = (style == esBool) || (strParamValue.convert(QVariant::Bool));
            if (!isCheck)
            {
                UiCommonDialog::ShowMessageBox(GBMP_TR(L"警告"), GBMP_TR(L"请输入布尔值"), (int)UiCommonDialog::ButtonType::OK);
                return false;
            }
        }
        else if (storageTypes == ParameterStorageType::Int)
        {
            isCheck = (style == esDropDown) || (strParamValue.convert(QVariant::Int));
            if (!isCheck)
            {
                UiCommonDialog::ShowMessageBox(GBMP_TR(L"警告"), GBMP_TR(L"请输入整数"), (int)UiCommonDialog::ButtonType::OK);
                return false;
            }
        }
        else if (storageTypes == ParameterStorageType::Double)
        {
            isCheck = strParamValue.convert(QVariant::Double);
            if (!isCheck)
            {
                UiCommonDialog::ShowMessageBox(GBMP_TR(L"警告"), GBMP_TR(L"请输入数值"), (int)UiCommonDialog::ButtonType::OK);
                return false;
            }
        }
    }

    //参数验证器只对值进行验证
    bool commitNow = false;
    OwnerPtr<IParameter> opNewParameter = param->Clone();
    OwnerPtr<IParameterValueStorage> opNewValStorge = nullptr;
    if (!GetCurrentParamValue(param, pItem, selElements, opNewValStorge, commitNow))
    {
        return false;
    }

    opNewParameter->SetParameterValueStorage(TransferOwnership(opNewValStorge));
    //没有验证器，默认为合法
    const IParameterValidator* pValidator = opNewParameter->GetValidator();
    if (!pValidator)
        return true;

    bool validateResult = true;
    std::wstring errorMessage;
    const IElement* pElement = nullptr;
    IDocument * pDoc = GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"文档指针为空，不合法",L"GDMP",L"2023-10-20");
    FOR_EACH(eleId, selElements)
    {
        pElement = pDoc->GetElement(eleId);
        if (pElement)
        {
            validateResult = pValidator->Validate(opNewParameter.get(), pElement, &errorMessage);
            if (!validateResult && !errorMessage.empty())
            {
                UiCommonDialog::ShowMessageBox(GBMP_TR(L"警告"), GBMP_TR(errorMessage), (int)UiCommonDialog::ButtonType::OK);
                return false;
            }
        }
    }
    return true;
}

bool PropertyPalette::UpdatePropertyItemToElementParameter(Sample::CPropertyItem* pItem, IElement* pElement,
    const std::vector<gcmp::ElementId>& selElements, bool& bCommitNow, bool& error)
{
    error = false; //更新错误标记
    if (pItem == nullptr || pElement == nullptr)
        return false;

    OwnerPtr<IParameter> param;
    if (pElement->GetElementParameters())
        param = pElement->GetElementParameters()->GetParameterById(pItem->UniqueID());
    if (!CheckParameterValid(pItem, param.get(), selElements))
        return false;

    //如果不显示此param，则略过
    if (param->GetParameterDefinition()->GetParameterTypeId() == PARAMETER_TYPE(None))
        return false;

    if (GetPreSetElementId().IsValid())
    {
        const IElementParameters* pElementParameters = pElement->GetElementParameters();
        if (pElementParameters &&
            !pElementParameters->IsPresetParameter(param->GetParameterDefinitionUid()))
        {
            return false;
        }
    }

    IDocument* pDocument = GetDocument();
    if (m_upUserTransaction == nullptr)
    {
        m_upUserTransaction = IUserTransaction::Create(pDocument, GBMP_TR(L"修改构件属性"), true);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(m_upUserTransaction, L"m_upUserTransaction为空",L"GDMP",L"2023-10-20");

    }
    if (m_upUserTransaction && m_upUserTransaction->IsStarted() == false)
    {
        m_upUserTransaction->Start();
    }

    bool bParameterChanged = false;
    OwnerPtr<IParameterValueStorage> opCurrentParamValue = nullptr;
    if (!GetCurrentParamValue(param.get(), pItem, selElements,
        opCurrentParamValue, bCommitNow))
        return false;

    if (!SaveParamValueToElement(pElement, param.get(), opCurrentParamValue,
        bParameterChanged))
    {
        error = true;
        return false;
    }
    UpdatePresetParamValue(bParameterChanged, pElement, param.get());

    // 参数的改变埋到当前Gux Action中，作为custom data
    if (bParameterChanged)
    {
        /*/
        gux::GuxClientUtil::LogCustomData(pItem->GetName().toStdWString(), pItem->GetValue().toString().toStdWString());
        */
    }

    return bParameterChanged;
}

bool PropertyPalette::SaveParamValueToElement(IElement* pElement, gcmp::IParameter* param,
    OwnerPtr<IParameterValueStorage> &opCurrentParamValue, bool &bParameterChanged)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMP",L"2023-10-20");

    if (opCurrentParamValue != nullptr)
    {
        IDocument * pDoc = GetDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"文档指针为空，不合法",L"GDMP",L"2023-10-20");

        const IParameterValueStorage* parameterValue = param->GetParameterValueStorage();
        if (parameterValue != nullptr && !parameterValue->HasSameValue(opCurrentParamValue.get()))
        {
            param->SetParameterValueStorage(TransferOwnership(opCurrentParamValue));
            std::wstring errorMsg;
            if (pElement->GetElementParameters() &&
                !pElement->GetElementParameters()->SetParameter(param, &errorMsg) &&
                !errorMsg.empty())
            {
                UiCommonDialog::ShowMessageBox(GBMP_TR(L"发生错误"), errorMsg, (int)UiCommonDialog::ButtonType::OK);
                return false;
            }
            bParameterChanged = true;
            return true;
        }
    }
    return true;
}

bool PropertyPalette::UpdatePresetParamValue(bool bParameterChanged, IElement* pElement, IParameter* param)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMP",L"2023-10-20");
    // update 预设参数中的值
    if (bParameterChanged && GetPreSetElementId().IsValid())
    {
        IPresetParameterManager* pPreSetMgr = IPresetParameterManager::Get(GetDocument());
        DBG_WARN_AND_RETURN_UNLESS(pPreSetMgr, false, L"pPreSetMgr为空",L"GDMP",L"2023-10-20");
        bool isOk{ false };
        Int32 categorySecondkey{ 0 };
#ifdef UiAdapter_IMPL
        isOk = UiAdapter::GetPresetValuesGroupId(GetDocument(), pElement, categorySecondkey);
        if (isOk)
        {
            return UiAdapter::SetPresetParameter(GetDocument(), pElement->GetBasicInformation()->GetCategoryUid(), categorySecondkey, param);
        }
#endif
        if (!isOk)
        {
            Int32 categorySecondkey = pPreSetMgr->GetPresetValuesGroupId(pElement);

            if (pPreSetMgr->SetPresetParameter(pElement->GetBasicInformation()->GetCategoryUid(), categorySecondkey, param))
                bParameterChanged = true;
        }

    }
    return bParameterChanged;
}

bool PropertyPalette::GetCurrentParamValue(const gcmp::IParameter* param, Sample::CPropertyItem* pItem,
    const std::vector<gcmp::ElementId> &elementIds, OwnerPtr<IParameterValueStorage> &opCurrentParamValue, bool &bCommitNow)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMP",L"2023-10-20");

    IDocument* pDoc = GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDocument为空",L"GDMP",L"2023-10-20");
    const IParameterDefinition* pParamDef = param->GetParameterDefinition();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pParamDef, L"pParamDef为空",L"GDMP",L"2023-10-20");
    IParameterDisplayManager* pParamDisplayMgr = IParameterDisplayManager::Get(pDoc);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pParamDisplayMgr, L"pParamDisplayMgr为空",L"GDMP",L"2023-10-20");
    const IParameterDisplay* parameterDisplay = pParamDisplayMgr->GetParameterDisplay(pParamDef);
    if (parameterDisplay == nullptr)
    {
        return false;
    }

    if (const IParameterDisplayDropdownList* pDropdownList = dynamic_cast<const IParameterDisplayDropdownList*>(parameterDisplay))
    {
        QString strCurValue = pItem->GetValue().toString();
        opCurrentParamValue = pDropdownList->GetValueByDisplayString(pDoc, strCurValue.toStdWString(), elementIds);
        if (!opCurrentParamValue)
        {
            return false;
        }
        if (pDropdownList->GetParameterValueList()->HasOuterEditor())
        {
            bCommitNow = true;
        }
    }
    else if (dynamic_cast<const IParameterDisplayEditbox*>(parameterDisplay) ||
        dynamic_cast<const IParameterDisplayEditboxWithButton*>(parameterDisplay))
    {
        // 普通显示
        QVariant itemValue = pItem->GetValue();
        if (itemValue.isValid())
        {
            QString strValue = itemValue.toString();
            // 滤除后缀
            if (param->GetParameterDefinition()->GetParameterTypeId() == PARAMETER_TYPE(Length))
            {
                strValue = strValue.left(strValue.indexOf(' '));
            }

            if (ParameterDisplayUtils::GetValueAsDisplayString(param) != strValue.toStdWString() && !strValue.isEmpty())
            {
                OwnerPtr<IParameter> opCurParam = param->Clone();
                ParameterDisplayUtils::SetValueFromDisplayString(opCurParam.get(), strValue.toStdWString());
                opCurrentParamValue = opCurParam->GetParameterValueStorage()->Clone();
            }
        }
    }
    else if (const IParameterDisplayCheckbox* pCheckbox = dynamic_cast<const IParameterDisplayCheckbox*>(parameterDisplay))
    {
        bool boolCurValue = pItem->GetValue().toBool();
        OwnerPtr<IParameter> opCurParam = param->Clone();
        opCurParam->SetValueAsBool(boolCurValue);
        opCurrentParamValue = opCurParam->GetParameterValueStorage()->Clone();
    }
    else if (const ParameterDisplayColorList* pColorList = dynamic_cast<const ParameterDisplayColorList*>(parameterDisplay))
    {
        if (pItem->GetValue().type() == QVariant::Color)
        {
            QColor color = pItem->GetValue().value<QColor>();
            int red = color.red();
            int green = color.green();
            int blue = color.blue();
            int alpha = color.alpha();
            Color colorData((unsigned char)red, (unsigned char)green, (unsigned char)blue, (unsigned char)alpha);

            int colorVal = *(int*)&colorData;
            if (param->GetValueAsInt() != colorVal)
            {
                OwnerPtr<IParameter> opCurParam = param->Clone();
                opCurParam->SetValueAsInt(colorVal);
                opCurrentParamValue = opCurParam->GetParameterValueStorage()->Clone();
            }
        }
    }

    const IParameterValueStorage* pValueStorage = param->GetParameterValueStorage();
    if (pValueStorage && opCurrentParamValue)
    {
        const IParameterValidator* pValidator = pValueStorage->GetValidator();
        if (pValidator)
            opCurrentParamValue->SetValidator(pValidator->Clone());
    }
    return opCurrentParamValue != nullptr;
}

bool PropertyPalette::UpdatePropertyItemToElement(int groupIndex, int propertyIndex)
{
    IDocument * pDocument = GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDocument, L"文档指针为空，不合法",L"GDMP",L"2023-10-20");

    std::vector<ElementId> selElements;
    GetShowElements(selElements);
    if (selElements.empty())
    {
        return false;
    }

    CInstancePropertyWidget* pIPW = GetComponentInstancePropertyWidget();
    DBG_WARN_AND_RETURN_UNLESS(pIPW != nullptr, false, L"pIPW为空",L"GDMP",L"2023-10-20");
    CPropertyItem* pItem = pIPW->GetPropertyByIndex(groupIndex, propertyIndex);
    DBG_WARN_AND_RETURN_UNLESS(pItem != nullptr, false, L"pItem不能为空",L"GDMP",L"2023-10-20");

    const IElement* pElement = pDocument->GetElement(selElements[0]);
    if (pElement == nullptr)
        return false;

    OwnerPtr<IParameter> param;
    if (pElement->GetElementParameters())
        param = pElement->GetElementParameters()->GetParameterById(pItem->UniqueID());
    if (!CheckParameterValid(pItem, param.get(), selElements))
        return false;

    //如果不显示此param，则略过
    if (param->GetParameterDefinition()->GetParameterTypeId() == PARAMETER_TYPE(None))
        return false;

    if (GetPreSetElementId().IsValid())
    {
        const IElementParameters* pElementParameters = pElement->GetElementParameters();
        if (pElementParameters &&
            !pElementParameters->IsPresetParameter(param->GetParameterDefinitionUid()))
        {
            return false;
        }
    }

    if (m_upUserTransaction == nullptr)
    {
        m_upUserTransaction = IUserTransaction::Create(pDocument, GBMP_TR(L"修改构件属性"), true);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(m_upUserTransaction, L"m_upUserTransaction为空",L"GDMP",L"2023-10-20");
    }
    if (m_upUserTransaction && m_upUserTransaction->IsStarted() == false)
    {
        m_upUserTransaction->Start();
    }

    bool bCommitAlways = false;
    OwnerPtr<IParameterValueStorage> opCurrentParamValue = nullptr;
    if (!GetCurrentParamValue(param.get(), pItem, selElements,
        opCurrentParamValue, bCommitAlways))
    {
        if (m_upUserTransaction && m_upUserTransaction->IsStarted())
        {
            m_upUserTransaction->Rollback();
        }
        return false;
    }

    bool isParameterChanged = false;
    FOR_EACH(sleEle, selElements)
    {
        IElement* pElement = pDocument->GetElement(sleEle);
        DBG_WARN_AND_RETURN_UNLESS(pElement != nullptr, false, L"pElement为空",L"GDMP",L"2023-10-20");
        bool isUpdateItem = false;
        if (pElement->GetElementParameters())
            param = pElement->GetElementParameters()->GetParameterById(pItem->UniqueID());
        bool error = SaveParamValueToElement(pElement, param.get(),
            opCurrentParamValue->Clone(), isUpdateItem);
        if (!error)
        {
            if (m_upUserTransaction && m_upUserTransaction->IsStarted())
            {
                m_upUserTransaction->Rollback();
                isParameterChanged = false;
                bCommitAlways = false;
            }
            break;
        }
        if (isUpdateItem == true)
        {
            isParameterChanged = true;
        }
        UpdatePresetParamValue(isParameterChanged, pElement, param.get());
    }
    if (m_upUserTransaction && bCommitAlways)
    {
        m_upUserTransaction->Commit();
        isParameterChanged = false;
    }

    //更新属性表
    UpdatePropertyTable();

    return isParameterChanged;
}

bool PropertyPalette::RefreshByParameterValueStorage(gcmp::IParameterValueStorage *pCurrentParamValue, int parameterDefinitionId)
{
    if (m_upUserTransaction == nullptr || !m_upUserTransaction->IsStarted())
    {
        DBG_WARN(L"事务未启动",L"GDMP",L"2023-10-20");
        return false;
    }

    gcmp::IDocument* pDocument = GetDocument();
    if (!pDocument)
    {
        return false;
    }

    std::vector<ElementId> selElements;
    GetShowElements(selElements);
    if (selElements.empty())
    {
        return false;
    }

    IHighlights::Get()->Clear();

    OwnerPtr<IParameter> param;
    bool isRollback = false;
    FOR_EACH(sleEle, selElements)
    {
        IElement* pElement = pDocument->GetElement(sleEle);
        DBG_WARN_AND_RETURN_UNLESS(pElement != nullptr, false, L"pElement为空",L"GDMP",L"2023-10-20");
        bool isUpdateItem = false;
        if (pElement->GetElementParameters())
            param = pElement->GetElementParameters()->GetParameterById(parameterDefinitionId);
        bool ok = SaveParamValueToElement(pElement, param.get(),
            pCurrentParamValue->Clone(), isUpdateItem);
        if (!ok)
        {
            isRollback = true;
            break;
        }

        UpdatePresetParamValue(isUpdateItem, pElement, param.get());
    }

    if (isRollback)
    {
        m_upUserTransaction->Rollback();
    }
    else
    {
        m_upUserTransaction->Commit();
    }

    ////更新可视化场景
    UpdateViewVisual();
    //更新属性表
    UpdatePropertyTable();
    Refresh(true);

    m_upUserTransaction->Start();

    return true;
}

void PropertyPalette::UpdatePropertyTableToElement()
{
    gcmp::IDocument* pDocument = GetDocument();
    if (!pDocument)
    {
        return;
    }

    std::vector<ElementId> selElements;
    GetShowElements(selElements);

    //将属性表内容设置到对象
    CInstancePropertyWidget* pIPW = GetComponentInstancePropertyWidget();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pIPW != nullptr, L"pIPW为空",L"GDMP",L"2023-10-20");

    bool isSolveSuccess = true;
    bool error = false;
    FOR_EACH(selEle, selElements)
    {
        IElement* pElement = pDocument->GetElement(selEle);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElement != nullptr, L"pElement为空",L"GDMP",L"2023-10-20");

        int groupNum = pIPW->GetPropertyGroupCount();
        for (int nGroup = 0; nGroup < groupNum; ++nGroup)
        {
            int propertyNum = pIPW->GetPropertyCount(nGroup);
            for (int np = 0; np < propertyNum; ++np)
            {
                CPropertyItem* pItem = pIPW->GetPropertyByIndex(nGroup, np);
                DBG_WARN_AND_CONTINUE_UNLESS(pItem != nullptr, L"pItem不能为空",L"GDMP",L"2023-10-20");
                bool bCommitAlways = false;
                UpdatePropertyItemToElementParameter(pItem, pElement, selElements, bCommitAlways, error);

                if (error)
                {
                    if (m_upUserTransaction && m_upUserTransaction->IsStarted())
                        m_upUserTransaction->Rollback();
                    break;
                }
            }
        }

        pElement->FinishEditing();
    }

    if (m_upUserTransaction && m_upUserTransaction->IsStarted())
    {
        if (isSolveSuccess)
        {
            //标记不需要更新整个属性表，避免提交事务导致更新
            m_bTransactionIsCommitting = true;
            m_upUserTransaction->Commit();
            m_bTransactionIsCommitting = false;
            m_isNeedUpdate = false;
        }
        else
        {
            m_upUserTransaction->Rollback();
        }
    }

    //更新可视化场景
    UpdateViewVisual();
    //更新属性表
    UpdatePropertyTable();
}

bool IsValidFamilyForInstance(const gcmp::IInstance* pInstance, const gcmp::IFamily* pFamily)
{
    if (!pInstance || !pFamily)
        return false;

    const IFamily* pInstanceFamily = pInstance->GetFamily();
    if (pInstanceFamily == nullptr)
        return false;

    if (pFamily->GetFamilyServiceUid().HasSameValue(pInstanceFamily->GetFamilyServiceUid()))
        return true;

    std::vector<const IFamilyType*> famTypes = pFamily->GetFamilyTypes();
    IDocument* pDoc = pInstance->GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMP",L"2023-10-20");

    return true;
}

void PropertyPalette::Refresh(bool bRebuild /*= false*/)
{
    //如窗口隐藏，没必要继续刷新
    if (!IsDockTopWidget())
    {
        return;
    }
    UpdateComponentType();// 更新类型列表
    UpdatePropertyTable(bRebuild);// 刷新属性表

    // 维护更新标记
    m_isNeedUpdate = false;
}

void PropertyPalette::ClearComponentType()
{
    CComponentTypeWidget *pComponentTypeWidget = GetComponentTypeWidget();
    pComponentTypeWidget->RemoveAllComponentTypeGroup();
}

void PropertyPalette::ShowViewComponentType()
{
    IDocument * pDoc = GetDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"文档指针为空，不合法",L"GDMP",L"2023-10-20");
    CComponentTypeWidget *pComponentTypeWidget = GetComponentTypeWidget();
    if (m_defaultElementId.IsValid())
    {
        IElement* pElement = pDoc->GetElement(m_defaultElementId);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElement != nullptr, L"默认对象为空",L"GDMP",L"2023-10-20");

        const IType* pType = pElement->GetBasicInformation()->GetType(); // 簇类型
        std::wstring typeName = (pType == nullptr) ? pElement->GetBasicInformation()->GetName() : pType->GetBasicInformation()->GetName();
        pComponentTypeWidget->AddComponentTypeGroup(0, 0, QString::fromStdWString(GBMP_TR(L"对象类型")), "");
        pComponentTypeWidget->AddComponentType(0, 0, 0, QString::fromStdWString(typeName), QString::fromStdWString(L":/PropertyDemo/Images/windowswitch.png"));
        pComponentTypeWidget->setCurrentComponentType(0, 0);
    }
    else
    {
        std::wstring viewTypeName;
        /////////////////////////////////////
        /*/
        ModelViewDlg* pModelViewDlg = dynamic_cast<ModelViewDlg*>(IModelViewDlg::Get(GBMP_MODELVIEW_DLG_NAME));
        QTreeWidgetItem* pSelectedViewPort = pModelViewDlg->GetSelectedViewPort();
        if (pSelectedViewPort)
        {
            viewTypeName = L"视口";
            pComponentTypeWidget->AddComponentTypeGroup(0, 0, QString::fromStdWString(GBMP_TR(L"视口名称")), "");
            pComponentTypeWidget->AddComponentType(0, 0, 0, QString::fromStdWString(viewTypeName), QString::fromStdWString(L":/PropertyDemo/Images/windowswitch.png"));
            pComponentTypeWidget->setCurrentComponentType(0, 0);
        }
        else
        {
        */
        IUiView* pUIView = IUiDocumentViewManager::Get()->GetCurrentUiView();
        if (pUIView == nullptr)
            return;

        IModelView* pModelView = pUIView->GetModelView();
        if (pModelView == nullptr)
            return;

        if (pModelView->GetViewType() == BuiltInViewType::Drawing)
        {
            // 图纸相关内容
#pragma warning(push)
#pragma warning(disable: 4996)
            std::wstring name = pModelView->GetName();
#pragma warning(pop)
            pComponentTypeWidget->AddComponentTypeGroup(0, 0, QString::fromStdWString(GBMP_TR(L"图纸名称")), "");
            pComponentTypeWidget->AddComponentType(0, 0, 0, QString::fromStdWString(name), QString::fromStdWString(L":/PropertyDemo/Images/windowswitch.png"));
            pComponentTypeWidget->setCurrentComponentType(0, 0);
        }
        else
        {
#pragma warning(push)
#pragma warning(disable: 4996)
            viewTypeName = pModelView->GetName();
#pragma warning(pop)
            // 视图相关内容
            pComponentTypeWidget->AddComponentTypeGroup(0, 0, QString::fromStdWString(GBMP_TR(L"视图名称")), "");
            pComponentTypeWidget->AddComponentType(0, 0, 0, QString::fromStdWString(viewTypeName), QString::fromStdWString(L":/PropertyDemo/Images/windowswitch.png"));
            pComponentTypeWidget->setCurrentComponentType(0, 0);
        }

    }
}

namespace
{
    // 还有一种方式是给IElementBasicInformation::GetType()增加传入参数IElement *。
    // 这是一个通性问题：引入非当前文档（数据集）的元素后，需要以<DataSet/Document Id, ElementId>来唯一表示对象。
    // 其实需要的是<AccountId, ProjectId, ModelId(DataSet/DocumentId), ElementId>这样的一组标识。
    const IType * GetElementType(const IElement * pElement)
    {
        if (nullptr == pElement)
        {
            return nullptr;
        }

        if (const ILinkElementProxy* pLinkElementProxy = quick_cast<ILinkElementProxy>(pElement))
        {
            const IElement* pLinkElement = pLinkElementProxy->GetLinkElement();
            if (nullptr == pLinkElement)
            {
                return nullptr;
            }
            const IElementBasicInformation * pBasicInformation = pLinkElement->GetBasicInformation();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pBasicInformation, L"无效pBasicInformation",L"GDMP",L"2023-10-20");
            return pBasicInformation->GetType();
        }
        else
        {
            const IElementBasicInformation * pBasicInformation = pElement->GetBasicInformation();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pBasicInformation, L"无效pBasicInformation",L"GDMP",L"2023-10-20");
            return pBasicInformation->GetType();
        }
    }
}

void PropertyPalette::UpdateComponentType()
{
    ClearComponentType();

    IDocument* pDocument = GetDocument();
    if (pDocument == nullptr)
    {
        return;
    }

    std::vector<ElementId> selElements = GetSourceElements().empty() ? GetSelectedElements() : GetSourceElements();
    if (selElements.empty())//没有选中对象，默认显示视图
    {
        ShowViewComponentType();
        return;
    }

    const IElement* pElement = pDocument->GetElement(selElements[0]);
    if (pElement == nullptr)
        return;

    const IType* pType = GetElementType(pElement);
    CComponentTypeWidget *pComponentTypeWidget = GetComponentTypeWidget();
    if (pComponentTypeWidget == nullptr)
        return;

    //TODO:这里可以添加支持内置构件，例如（标高、轴网等）
    if (pType == nullptr)
    {
        std::wstring typeName = pElement->GetBasicInformation()->GetDefaultTypeName();
        if (typeName.empty())
            return;

        pComponentTypeWidget->AddComponentTypeGroup(0, 0, QString::fromStdWString(typeName), "");
        pComponentTypeWidget->AddComponentType(0, 0, 0, QString::fromStdWString(typeName), QString::fromStdWString(L":/PropertyDemo/Images/windowswitch.png"));
        pComponentTypeWidget->setCurrentComponentType(0, 0);
        return;
    }

    //多类型处理
    for (int idx = 0; idx < (int)selElements.size(); ++idx)
    {
        const IElement* pSelElement = pDocument->GetElement(selElements[idx]);
        if (pSelElement == nullptr)
            return;

        const IType * pCurType = GetElementType(pSelElement);

        if (pCurType == nullptr)
            return;

        if (pType->GetBasicInformation()->GetCategoryUid() != pCurType->GetBasicInformation()->GetCategoryUid())
        {
            pComponentTypeWidget->DisplayMultiValState(QString::fromStdWString(GBMP_TR(L"*多种*")), QString::fromStdWString(L":/images/GBM.png"));
            return;
        }

        const IInstanceType* pInstanceType = quick_cast<const IInstanceType>(pType);
        const IInstanceType* pCurInstanceType = quick_cast<const IInstanceType>(pCurType);
        if (pInstanceType && pCurInstanceType)
        {
            if (pInstanceType->GetFamilyId() != pCurInstanceType->GetFamilyId())
            {
                pComponentTypeWidget->DisplayMultiValState(QString::fromStdWString(GBMP_TR(L"*多种*")), QString::fromStdWString(L":/images/GBM.png"));
                return;
            }
        }

        pType = pCurType;
    }

    ElementTypeGroups typeGroupVec;
    if (selElements.size() >= 1)
    {
        const IInstance* pSelectInstance = quick_cast<const IInstance>(pElement);
        if (pSelectInstance)
        {
            if (pSelectInstance->GetSuperInstanceId().IsValid())
            {
                const IElementBasicInformation* pBasicInfo = pSelectInstance->GetBasicInformation();
                DBG_WARN_AND_RETURN_VOID_UNLESS(pBasicInfo, L"基本信息组件为空",L"GDMP",L"2023-10-20");
                IInstanceType* pInstanceType = quick_cast<IInstanceType>(pBasicInfo->GetType());
                DBG_WARN_AND_RETURN_VOID_UNLESS(pInstanceType, L"获取类型为空",L"GDMP",L"2023-10-20");

                const ElementId& topFamilyId = pInstanceType->GetTopFamilyId();
                const IFamily* pTopFamily = quick_cast<IFamily>(pDocument->GetElement(topFamilyId));
                DBG_WARN_AND_RETURN_VOID_UNLESS(pTopFamily, L"获取主构件为空",L"GDMP",L"2023-10-20");
                std::vector<const IFamilyType*> pFamilyTypes = pTopFamily->GetAllSubFamilyTypesBySubInstanceType(pInstanceType);
                std::vector<ElementTypeInfo> typeInfoVec;
                FOR_EACH(pFamilyType, pFamilyTypes)
                {
                    DBG_WARN_AND_CONTINUE_UNLESS(pFamilyType, L"族类型为空",L"GDMP",L"2023-10-20");
                    ElementTypeInfo newTypeInfo = std::make_tuple(
                        pInstanceType->GetElementId().GetId()
                        , pFamilyType->GetName()
                        , L":images/Common/属性.png"); 
                    typeInfoVec.push_back(std::move(newTypeInfo));
                }

                ElementTypeGroup newTypeGroup = std::make_tuple(std::make_tuple(pInstanceType->GetElementId().AsInt64(), pTopFamily->GetSubFamilyNameBySubInstanceType(pInstanceType), L""), std::move(typeInfoVec));
                typeGroupVec.push_back(std::move(newTypeGroup));
            }
            else
            {
                const UniIdentity& selectElementCategroyUid = pElement->GetBasicInformation()->GetCategoryUid();

                std::vector<const IFamily*> similarFamilies;
                std::vector<IFamily*> allFamilies = IFamily::GetAllFamilies(pDocument);
                FOR_EACH(pFamily, allFamilies)
                {
                    if (pFamily->GetBasicInformation()->GetCategoryUid() != selectElementCategroyUid)
                        continue;

                    if (IsValidFamilyForInstance(pSelectInstance, pFamily))
                    {
                        similarFamilies.push_back(pFamily);
                    }
                }

                for (auto itFam : similarFamilies)
                {
                    std::vector<ElementTypeInfo> typeInfoVec;
                    auto typeList = itFam->GetInstanceTypes();
                    for (auto itType = typeList.begin(); itType != typeList.end(); ++itType)
                    {
                        ElementTypeInfo newTypeInfo = std::make_tuple(
                            (*itType)->GetBasicInformation()->GetElementId().GetId()
                            , (*itType)->GetBasicInformation()->GetName()
                            , L":images/Common/属性.png");
                        typeInfoVec.push_back(std::move(newTypeInfo));
                    }
                    ElementTypeGroup newTypeGroup = std::make_tuple(std::make_tuple(itFam->GetElementId().AsInt64(), itFam->GetBasicInformation()->GetName(), L""), std::move(typeInfoVec));
                    typeGroupVec.push_back(std::move(newTypeGroup));
                }
            }
        }
        if (const ILinkElementProxy* pLinkElementProxy = quick_cast<ILinkElementProxy>(pElement))
        {
            std::vector<ElementTypeInfo> typeInfoVec;
            ElementTypeInfo newTypeInfo = std::make_tuple(pType->GetBasicInformation()->GetElementId().GetId()
                , pType->GetBasicInformation()->GetName(), L"");
            typeInfoVec.push_back(std::move(newTypeInfo));
            ElementTypeGroup newTypeGroup = std::make_tuple(std::make_tuple(pType->GetElementId().AsInt64(), pType->GetBasicInformation()->GetName(), L""), std::move(typeInfoVec));
            typeGroupVec.push_back(std::move(newTypeGroup));
        }
        if (const ILinkDocumentElement* pLinkDocElement = quick_cast<ILinkDocumentElement>(pElement))
        {
            std::vector<ElementTypeInfo> typeInfoVec;
            ElementTypeInfo newTypeInfo = std::make_tuple(pType->GetBasicInformation()->GetElementId().GetId()
                , pElement->GetBasicInformation()->GetName(), L"");
            typeInfoVec.push_back(std::move(newTypeInfo));
            ElementTypeGroup newTypeGroup = std::make_tuple(std::make_tuple(pType->GetElementId().AsInt64(), pType->GetBasicInformation()->GetName(), L""), std::move(typeInfoVec));
            typeGroupVec.push_back(std::move(newTypeGroup));
        }
    }

    int groupIdx = 0;
    for (auto& typeGroup : typeGroupVec)
    {
        auto groupInfo = std::get<0>(typeGroup);
        pComponentTypeWidget->AddComponentTypeGroup(groupIdx
            , std::get<0>(groupInfo)
            , QString::fromStdWString(std::get<1>(groupInfo))
            , QString::fromStdWString(std::get<2>(groupInfo)));

        int typeIdx = 0;
        auto typeInfoVec = std::get<1>(typeGroup);
        for (auto& typeInfo : typeInfoVec)
        {
            pComponentTypeWidget->AddComponentType(groupIdx
                , typeIdx
                , std::get<0>(typeInfo)
                , QString::fromStdWString(std::get<1>(typeInfo))
                , QString::fromStdWString(std::get<2>(typeInfo)));
            if (pType->GetBasicInformation()->GetElementId().GetId() == std::get<0>(typeInfo)
                && pType->GetBasicInformation()->GetName() == std::get<1>(typeInfo))
            {
                pComponentTypeWidget->setCurrentComponentType(groupIdx, typeIdx);
            }
            typeIdx++;
        }
        groupIdx++;
    }
    SetStatusOfAddAndModifyButton();
    SetStatusOfComponentTypeComboBox();
}

void PropertyPalette::OnPropertyBindButtonClicked(int uniquiID)
{
    IDocument* pDocument = GetDocument();
    if (pDocument == nullptr)
        return;

    std::vector<ElementId> selElements;
    GetShowElements(selElements);
    if (selElements.empty())
        return;
}

void PropertyPalette::onPropertyEditButtonClicked(int uniquiID)
{
    std::vector<ElementId> selElements;
    GetShowElements(selElements);
    if (selElements.empty())
        return;

    PropertyPanelEventArgs inputArgs(L"PropertyItemButtonClicked", L"");
    inputArgs.SetPropertyItemUniqueId(StringUtil::ToWString(uniquiID));
    m_inputEvent->Emit(&inputArgs);
    return;
}

void PropertyPalette::GroupAndSortParameters(IDocument* pDocument, const IElement* pElement,
    const std::vector<ElementId>& selElements, const std::vector<OwnerPtr<IParameter>>& commonParams,
    const std::vector<bool>& paramMultiVals, GroupParametersArray& outGroupParameters,
    std::map<int, bool>& outParamDefIdToIsParamMultiVals) const
{
    outGroupParameters.clear();

    std::map<UniIdentity, int> paramUidToParamIdx; // <ParamDefinitonUid, index_in_commonParams>
    std::map<int, bool> paramDefIdToIsParamMultiVals; //<ParamDefinitionId, is_param_multi_val>

    // 把 commonParams 中参数分组
    std::vector<const IParameterDefinition*> allParameterDefs;
    for (int tmpParamIdx = 0; tmpParamIdx < (int)commonParams.size(); tmpParamIdx++)
    {
        const IParameterDefinition* paramDef = commonParams[tmpParamIdx]->GetParameterDefinition();
        allParameterDefs.push_back(paramDef);

        // Uid->index
        if (paramUidToParamIdx.find(paramDef->GetUid()) == paramUidToParamIdx.end())
        {
            paramUidToParamIdx.insert(std::make_pair(paramDef->GetUid(), tmpParamIdx));
        }
        else
        {
            DBG_WARN(L"两个参数具有同样的DefinitionId",L"GDMP",L"2023-10-20");
        }

        // paramdefid->is_param_multi_val
        paramDefIdToIsParamMultiVals.insert(std::make_pair(paramDef->GetId(), paramMultiVals[tmpParamIdx]));
    }

#pragma region 此处使用IParameterGroupsFilter只是为了拿到GroupName并进行预排序，如需复用请将此处FIlter相关代码移入之后的Sorter中，在Sorter中直接拿GroupName和预排序，并移动Filter相关文件到合理位置
    const IParameterGroupsFilter* pGroupsFilter = IParameterGroupsFilter::GetParameterGroupsFilter();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGroupsFilter != nullptr, L"pGroupsFilter为空",L"GDMP",L"2023-10-20");
    std::unordered_set<std::wstring> unorderGroupNames;
    FOR_EACH(paramDef, allParameterDefs)
    {
        std::wstring groupName = pGroupsFilter->GetGroupName(paramDef);
        unorderGroupNames.emplace(groupName);
    }

    //GCMP平台层次的参数分组以及参数排序
    std::vector<std::wstring> allGroupNames(unorderGroupNames.begin(), unorderGroupNames.end());
    std::vector<size_t> groupsOrder = pGroupsFilter->SortGroups(allGroupNames);             //组别排序
    std::vector<size_t> parametersOrder = pGroupsFilter->SortParameters(allParameterDefs);  //参数排序

    // 组织参数分组数据，为进行具体产品平台调整参数分组、顺序做准备
    GroupParameterUidsArray allGroupParameterUids;
    {
        // group
        for (int groupOrderIdx = 0; groupOrderIdx < (int)groupsOrder.size(); groupOrderIdx++)
        {
            std::vector<UniIdentity> emptyParams;
            const std::wstring& gname = allGroupNames[groupsOrder[groupOrderIdx]];

            allGroupParameterUids.push_back(std::make_pair(gname, emptyParams));
        }

        // add parameters to each group
        for (int paramOrderIdx = 0; paramOrderIdx < (int)parametersOrder.size(); paramOrderIdx++)
        {
            const IParameterDefinition* tmpParamDef = allParameterDefs[parametersOrder[paramOrderIdx]];
            DBG_WARN_AND_CONTINUE_UNLESS(tmpParamDef, L"tmpParamDef为空",L"GDMP",L"2023-10-20");
            const std::wstring& gname = pGroupsFilter->GetGroupName(tmpParamDef);//allParameterDefs[paramIdx].GetData().GetGroupName();
            FOR_EACH(item, allGroupParameterUids)
            {
                if (item.first == gname)
                {
                    item.second.push_back(tmpParamDef->GetUid());
                    break;
                }
            }
        }
    }

    // 产品层次的整体参数分组、参数次序
    GroupParameterUidsArray defOutGroupParameters;
    if (IElementParameterGroupSorterManager::GetSorter() != nullptr)
    {
        IElementParameterGroupSorterManager::GetSorter()->GroupAndSortParameters(allGroupParameterUids, defOutGroupParameters);
    }
    else
    {
        defOutGroupParameters.swap(allGroupParameterUids);
    }

    GroupParameterUidsArray sortedGroupParameterUids;
    if (selElements.size() == 1)
    {
        // 单选再看element的实例参数是否需要调整分组以及次序
        const IElementParameters* pElementParams = pElement->GetElementParameters();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElementParams, L"element parameters不应为空",L"GDMP",L"2023-10-20");
        const IElementParameterGroupOverride* pGroupOverride = pElementParams->GetElementParameterGroupOverride();
        sortedGroupParameterUids = defOutGroupParameters;
        if (pGroupOverride)
            pGroupOverride->AdjustParameterGroup(defOutGroupParameters, sortedGroupParameterUids);
        else
            sortedGroupParameterUids.swap(defOutGroupParameters);
    }
    else
    {
        // 多选暂不进行参数实例层次调整
        sortedGroupParameterUids.swap(defOutGroupParameters);
    }
#pragma endregion

    // 输出outGroupParameters & outParamDefIdToIsParamMultiVals
    FOR_EACH(pairItem, sortedGroupParameterUids)
    {
        std::vector<OwnerPtr<IParameter>> eachGroupParameters;
        FOR_EACH(parameterUid, pairItem.second)
        {
            eachGroupParameters.emplace_back(commonParams[paramUidToParamIdx[parameterUid]]->Clone());
        }

        outGroupParameters.emplace_back(std::make_pair(pairItem.first, TransferOwnership(eachGroupParameters)));
    }

    outParamDefIdToIsParamMultiVals.swap(paramDefIdToIsParamMultiVals);
}

void PropertyPalette::UpdatePropertyTable(bool bRebuild /*= false*/)
{
    if (!m_canPropertyTableBeUpdated)
        return;

    CInstancePropertyWidget* pIPW = GetComponentInstancePropertyWidget();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pIPW != nullptr, L"pIPW为空",L"GDMP",L"2023-10-20");
    pIPW->RemoveAllPropertyGroup();

    IDocument* pDocument = GetDocument();
    if (pDocument == nullptr)
    {
        return;
    }

    std::vector<ElementId> selElements;
    GetShowElements(selElements);
    if (selElements.empty())
        return;

    const IElement* pElement = pDocument->GetElement(selElements[0]);
    if (pElement == nullptr)
    {
        return;
    }

    if (pDocument->IsFamilyDocument())
    {
        pIPW->SetBindButtonColomnVisible(true);
    }
    else
    {
        pIPW->SetBindButtonColomnVisible(false);
    }

    //  标记值是否完全相同，相同则显示值，否则显示空
    //      check不同则显示未选中
    //      下拉ComBox可选项完全相同才显示
    std::vector<OwnerPtr<IParameter>> commonParams;
    std::vector<bool> paramMultiVals;
    GetCommonParameters(pDocument, pElement, selElements, commonParams, paramMultiVals);

    // 参数分组、排序
    GroupParametersArray finalOutGroupParameters;
    std::map<int, bool> paramDefIdToIsParamMultiVals;
    GroupAndSortParameters(pDocument, pElement, selElements, commonParams, paramMultiVals, finalOutGroupParameters, paramDefIdToIsParamMultiVals);

    // 创建参数组
    int groupId = 0;
    bool isCurView = IsCurModelViewShow(selElements);
    const IParameterDefinitionLibrary* pParamDefLib = IParameterDefinitionLibrary::Get(pDocument);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParamDefLib != nullptr, L"pParamDefLib为空",L"GDMP",L"2023-10-20");
    const int elementNameParamDefId = pParamDefLib->GetParameterDefinitionIdByUid(PARAMETER_UID(ElementNameBuiltInParameter));

    FOR_EACH(curParamGroupItem, finalOutGroupParameters)
    {
        // 添加参数分组
        //注意：groupId < 0 ,(控件内部只用一个容器存放，防止与属性项ID重叠)
        const std::wstring& curGroupName = curParamGroupItem.first;
        const std::vector<OwnerPtr<IParameter>>& curGroupParams = curParamGroupItem.second;

        // 如果组内参数为空，则不显示空组
        if (curGroupParams.empty())
            continue;

        QString qstrGroupName = QString::fromStdWString(curGroupName);
        pIPW->AddPropertyGroup(--groupId, qstrGroupName, qstrGroupName);

        // 添加分组下的所有参数
        for (int loop = 0; loop < (int)curGroupParams.size(); ++loop)
        {
            const IParameter* opCurParam = curGroupParams[loop].get();
            if (!opCurParam->IsUserVisible())
            {
                continue;
            }

            int curParamDefId = opCurParam->GetParameterDefinitionId();
            const IParameterDefinition * pCurParamDef = opCurParam->GetParameterDefinition();
            DBG_WARN_AND_CONTINUE_UNLESS(pCurParamDef, L"通过参数获取的参数定义指针为空，不合法",L"GDMP",L"2023-10-20");
            std::wstring originParamName = pCurParamDef->GetName();
            std::wstring paramName = opCurParam->GetName();
            std::wstring paramValue = ParameterDisplayUtils::GetValueAsDisplayString(opCurParam);

            // 特殊处理-“视图名称”属性
            bool isNameParam = (curParamDefId == elementNameParamDefId);
            if (isCurView && isNameParam)
            {
                paramName = GBMP_TR(L"视图名称");
                paramValue = opCurParam->GetValueAsString();
            }

            // 预设参数
            if (GetPreSetElementId().IsValid())
            {
                const IElementParameters* pElementParameters = pElement->GetElementParameters();
                if (pElementParameters &&
                    !pElementParameters->IsPresetParameter(pCurParamDef->GetUid()))
                {
                    continue;
                }
            }

            CPropertyGroupItem* pGroupItem = pIPW->GetPropertyGroupByName(QString::fromStdWString(curGroupName));
            if (nullptr == pGroupItem)
                continue;

            std::wstring paramDescription = pCurParamDef->GetDescription();

            CPropertyItem* pItem = pIPW->AddProperty(pGroupItem->GetGroupIndex(), curParamDefId,
                QString::fromStdWString(paramName), QString::fromStdWString(paramDescription), QString::fromStdWString(paramValue),
                true, esLineEdit, opCurParam->IsBindable());

            pItem->SetOriginParamName(QString::fromStdWString(originParamName));

            // 目前对于参数是否可修改的校验规则如下：
            // 对于ParameterProcessType::GeneralOutput型和ParameterProcessType::Bound型的参数，直接认为该参数不可修改，不采用用户自定义behavior返回的可修改性判断。
            // 对于非ParameterProcessType::GeneralOutput型和非ParameterProcessType::Bound型的参数，再进一步获取用户设定的是否可修改的属性。
            {
                const IElementParameters* pEleBehavior = pElement->GetElementParameters();
                if (pEleBehavior)
                {
                    if (!pEleBehavior->IsParameterModifiable(curParamDefId))
                    {
                        pItem->SetEditStyle(esNone);
                        pItem->SetEnable(false);
                    }
                }
            }

            SetPropertyItemValue(pItem, opCurParam, selElements, paramDefIdToIsParamMultiVals[curParamDefId]);
        }
    }
    pIPW->RefreshView(bRebuild);
}

void PropertyPalette::SetPropertyItemValue(CPropertyItem* pItem, const IParameter* param,
    const std::vector<ElementId> &elementIds, bool isMultiValue)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(param, L"param is null.",L"GDMP",L"2023-10-20");

    const gcmp::IDocument* pDocument = GetDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDocument, L"pDocument为空",L"GDMP",L"2023-10-20");
    const IParameterDefinition* pParamDef = param->GetParameterDefinition();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParamDef, L"pParamDef为空",L"GDMP",L"2023-10-20");
    IParameterDisplayManager* pParamDisplayMgr = IParameterDisplayManager::Get(pDocument);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParamDisplayMgr, L"pParamDisplayMgr为空",L"GDMP",L"2023-10-20");
    const IParameterDisplay* parameterDisplay = pParamDisplayMgr->GetParameterDisplay(pParamDef);
    if (parameterDisplay == nullptr)
    {
        return;
    }

    if (const IParameterDisplayDropdownList * dropdownList = dynamic_cast<const IParameterDisplayDropdownList *>(parameterDisplay))
    {
        QStringList strList;
        std::vector<std::wstring>  displayStrings = dropdownList->GetDisplayStrings(pDocument, elementIds);
        const gcmp::IDocument* pDoc = pDocument;
        if ((int)elementIds.size() > 0)
        {
            const IElement* pSelEle = pDocument->GetElement(elementIds[0]);
            const ILinkElementProxy* pProxy = quick_cast<ILinkElementProxy>(pSelEle);
            if (pProxy)
            {
                const ILinkDocumentElement* plinkDocumentElement = pProxy->GetLinkDocumentElement();
                DBG_WARN_AND_RETURN_VOID_UNLESS(plinkDocumentElement, L"plinkDocumentElement为空",L"GDMP",L"2023-10-20");
                const IDocument* pLinkDocment = plinkDocumentElement->GetLinkDocument();
                if (pLinkDocment)
                {
                    pDoc = pLinkDocment;
                }
            }
        }
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDocument, L"pDocument为空",L"GDMP",L"2023-10-20");
        const std::wstring& paramDisplayStr = dropdownList->GetDisplayStringByValue(pDoc, param->GetParameterValueStorage());

        {
            if (param->GetParameterDefinitionId() == PARAMETER_ID(ViewScaleBuiltInParameter))
            {
                if (std::find(displayStrings.begin(), displayStrings.end(), paramDisplayStr) == displayStrings.end())
                {
                    displayStrings.push_back(paramDisplayStr);
                }
            }
        }

        FOR_EACH(displayStr, displayStrings)
        {
            strList << QString::fromStdWString(displayStr);
        }

        pItem->SetEditStyle(esDropDown);
        pItem->SetComboboxItems(strList);

        pItem->SetValue(QString::fromStdWString(paramDisplayStr));
        pItem->SetIsMultiValue(isMultiValue);
        pItem->SetManualInputModifiable(dropdownList->IsManualInputModifiable(pDocument));

    }
    else if (const IParameterDisplayEditbox* editbox = dynamic_cast<const IParameterDisplayEditbox *>(parameterDisplay))
    {
        // 普通显示
        if (isMultiValue)
            pItem->SetIsMultiValue(true);
    }
    else if (const IParameterDisplayEditboxWithButton * editbox = dynamic_cast<const IParameterDisplayEditboxWithButton *>(parameterDisplay))
    {
        pItem->SetEditStyle(esLineEllipsis);
        // 普通显示
        if (isMultiValue)
        {
            pItem->SetValue(QString(""));
        }
        else
        {
            std::wstring paramDisplayStr = ParameterDisplayUtils::GetValueAsDisplayString(param);
            pItem->SetValue(QString::fromStdWString(paramDisplayStr));
        }
    }
    else if (const IParameterDisplayCheckbox * checkbox = dynamic_cast<const IParameterDisplayCheckbox *>(parameterDisplay))
    {
        pItem->SetEditStyle(esBool);
        if (isMultiValue == false)
            pItem->SetValue(param->GetValueAsBool() ? Qt::Checked : Qt::Unchecked);
        else
        {
            pItem->SetValue(Qt::PartiallyChecked);
            pItem->SetIsMultiValue(true);
        }
    }
    else if (const ParameterDisplayColorList *pColorList = dynamic_cast<const ParameterDisplayColorList*>(parameterDisplay))
    {
        pItem->SetEditStyle(esColorList);
        pItem->SetIsMultiValue(isMultiValue);
        //pItem->SetComboboxItems(pColorList);

        int colorVal = param->GetValueAsInt();
        unsigned char* colorData = (unsigned char*)(&colorVal);
        int red = colorData[0];
        int green = colorData[1];
        int blue = colorData[2];
        int alpha = colorData[3];
        QVariant color(QColor(red, green, blue, alpha));
        pItem->SetValue(color);
    }
}

// 主动更新View，同步可视化效果
void PropertyPalette::UpdateViewVisual()
{
    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocViewMgr != nullptr, L"pUiDocViewMgr为空",L"GDMP",L"2023-10-20");

    IUiDocument* pUIDoc = pUiDocViewMgr->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIDoc != nullptr, L"pUIDoc为空",L"GDMP",L"2023-10-20");

    pUIDoc->UpdateView();
}

void PropertyPalette::SetDefaultElementId(const gcmp::ElementId& idDefaultElement)
{
    m_defaultElementId = idDefaultElement;
    Refresh(false);
}

void PropertyPalette::SetPreSetElementId(const gcmp::ElementId& elementId)
{
    m_tmpPreSetElementId = elementId;
}
const ElementId PropertyPalette::GetPreSetElementId() const
{
    return m_tmpPreSetElementId;
}

void PropertyPalette::UpdateStatus()
{
    RefreshAll();
}

IPropertyPanelEvent* PropertyPalette::GetInputEvent()
{
    return m_inputEvent.get();
}

